package com.md.common.utils.security;

import org.bouncycastle.jce.provider.BouncyCastleProvider;

import javax.crypto.Cipher;
import java.io.*;
import java.math.BigInteger;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.RSAPrivateKeySpec;
import java.security.spec.RSAPublicKeySpec;
import java.util.HashMap;
import java.util.Map;

/**
 * 功能描述：加密接口请求参数解密工具
 *
 * @author lujianping@oak168.com
 * @version 1.0
 * @date 2018-08-16 11:10
 * @since JDK 1.8
 */
public class RSAUtils {
	public static final int KEYSIZE = 512;

    private static RSAPublicKey pubKey;
    private static RSAPrivateKey priKey;
	
	public static void main(String[] args) throws Exception {
		RSAUtils rsa = new RSAUtils();
//        Map<String,Object> key = rsa.createKey();
//        RSAPublicKey publicKey =  (RSAPublicKey)key.get("publicKey");
//        RSAPrivateKey privateKey = (RSAPrivateKey)key.get("privateKey");
//		//模
//		String Modulus = publicKey.getModulus().toString(16);
//		//公钥指数
//		String Exponent = publicKey.getPublicExponent().toString(16);
//		//私钥指数
//        String private_exponent = privateKey.getPrivateExponent().toString(16);

        String Modulus = "9c8ca1a54172f2acea6049b6ebb335dc18861ed4f8bd9dc951f306cbe474500d4e0efb2e31b52b316ad3463ffc4f3bd57be5269e40a1325a8328cb4b7081c47b";
        String Exponent = "10001";
        String private_exponent = "344c069eb383e2edeb9e1f0201db41b2dfbe6e5901d4d651301485160d4b8ddcb3359e3589c386a29f432ad98e9f46d27b2d8818e72f78ae8470fff15fc5599";

		System.out.println("Exponent:"+Exponent);
		System.out.println("Modulus:"+Modulus);
        System.out.println("private_exponent:"+private_exponent);


		//使用模和指数获取公钥
		RSAPublicKey pukey = getPublicKey(Modulus, Exponent);
		RSAPrivateKey prkey = getPrivateKey(Modulus.toString(),private_exponent);

		String jspwd ="183974045525939ba34a7809bb5b059a69b49930591c2981aaf23d0f5fbbcf1c0f9a293dae3629a6b9f7e6fe16bb364c14e98335b9d57b6b6669bd73d355149e 2333a4f9fcbbf51719929b467c6f1b1d5c939336313c5d9c7656f8b5ea828f18b51d221c3818ac3d0cc1df0c73a1ee3363abe0e84cf99c5c793e5fdb13c8ec7b";
        jspwd = "7a05c791024e30a9b51a8f72f7f0c0beba162e84f0839305aa4504a16701e32c860c38d1d22c0d2dbf41075901dfa323fc9a0abf4a8929bf45945fee80f47a45 2333a4f9fcbbf51719929b467c6f1b1d5c939336313c5d9c7656f8b5ea828f18b51d221c3818ac3d0cc1df0c73a1ee3363abe0e84cf99c5c793e5fdb13c8ec7b";
        RandUtil rand = new RandUtil();
		String data2 = rsa.decrypttoStr(prkey,jspwd);
		System.out.println("解密后内容："+ data2);
	}

    /**
     * 初始化
     * @param modulus
     * @param public_exponent
     * @param private_exponent
     */
    public static void init(String modulus, String public_exponent, String private_exponent){
        pubKey = getPublicKey(modulus, public_exponent);
        priKey = getPrivateKey(modulus, private_exponent);
    }
	
	/**
	 * 加密
	 * @param publicKey 公钥
	 * @param content 需要加密的内容
	 * @return
	 * @throws Exception
	 */
	public static String encrypttoStr(Key publicKey,String content) throws Exception{
		String endata = RandUtil.parseByte2HexStr(publicEnrypy(publicKey,content));
		return endata;
	}
	
	/**
	 * 解密
	 * @param privateKey 私钥
	 * @param endata 需要解密的内容
	 * @return
	 * @throws Exception
	 */
	private static String decrypttoStr(Key privateKey,String endata) throws Exception{
        //前端加密是用了分块加密方式，块和块之间用空格隔开了，这里解密时也一样需要分块解密，而且密文块是倒序排列，块的获取也需要从后向前取出进行解密
        String[] enBlocks = endata.split(" ");//分块解密
        StringBuilder sb = new StringBuilder();
        for(int i = enBlocks.length - 1;i >= 0 ; i--){
            String decryptedBlock = new String(privateEncode(privateKey, RandUtil.parseHexStr2Byte(enBlocks[i])));
            sb.append(decryptedBlock);
        }
		return sb.reverse().toString();
	}

    /**
     * 解密
     * @param endata 需要解密的内容
     * @return
     * @throws Exception
     */
    public static String decrypttoStr(String endata) throws Exception{
        return decrypttoStr(priKey, endata);
    }
	
	public static String decrypttoStr_normal(Key privateKey,String endata) throws Exception{
		String data = new String(privateEncode(privateKey,endata.getBytes()));
		return data;
	}
	
	
	 /**
	  * 加密的方法,使用公钥进行加密
	  * @param publicKey 公钥
	  * @param data 需要加密的数据
	  * @throws Exception
	  */
    public static byte[] publicEnrypy(Key publicKey,String data) throws Exception {
 
        Cipher cipher = Cipher.getInstance("RSA",new BouncyCastleProvider());
 
        // 设置为加密模式
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
 
        // 对数据进行加密
        byte[] result = cipher.doFinal(data.getBytes());

        
        return result;
    }
 
    /**
     * 解密的方法，使用私钥进行解密
     * privateKey  私钥
     * encoData 需要解密的数据
     * @throws Exception
     */
    private static byte[]  privateEncode(Key privateKey,byte[] encoData) throws Exception {
        Cipher cipher = Cipher.getInstance("RSA",new BouncyCastleProvider());
          
        //设置为解密模式，用私钥解密
         cipher.init(Cipher.DECRYPT_MODE, privateKey);
         //解密
         byte[] data = cipher.doFinal(encoData);
//         System.out.println("解密后的数据："+data);
         return data;
    }
    
    
    
    /**
	 * 自动生成密钥对
	 * @throws Exception
	 */
	public  Map<String,Object> createKey(){
		
		 	try {
//				Cipher cipher = Cipher.getInstance("RSA");
		        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA", new BouncyCastleProvider());
				
		        SecureRandom random = new SecureRandom();  
		        keyPairGenerator.initialize(RSAUtils.KEYSIZE, random);
		 
		        // 生成钥匙对
		        KeyPair keyPair = keyPairGenerator.generateKeyPair();
		 
		        // 得到公钥
		        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
		        // 得到私钥
		        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
		        
		        Map<String,Object> map = new HashMap<String, Object>();
		        map.put("publicKey", publicKey);
		        map.put("privateKey", privateKey);
		 
		        return map;
		        //把私钥保存到硬盘上
	//	        saveKey(privateKey,"E://private_key");
		      //把公钥保存到硬盘上
	//	        saveKey(publicKey,"E://public_key");
		 	} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				return null;
			} 
		
	}
     
      
    /**
     * 从硬盘中加载私钥
     * @return
     * @throws IOException
     * @throws FileNotFoundException
     * @throws ClassNotFoundException
     */
    public  Key loadKey(String keyUrl) throws IOException, FileNotFoundException,
            ClassNotFoundException {
        ObjectInputStream inputStream = new ObjectInputStream(
                new FileInputStream(new File(keyUrl)));
        Key key = (Key) inputStream.readObject();
        return key;
    }
   
     
    /**
     * 把私钥或则公钥保存到硬盘上
     * @throws IOException
     * @throws FileNotFoundException
     */
    private  void saveKey(Key key,String saveUrl) throws IOException,
            FileNotFoundException {
        ObjectOutputStream outputStream = new ObjectOutputStream(
                new FileOutputStream(new File(saveUrl)));
        outputStream.writeObject(key);
    }
    
    /**  
     * 使用模和指数生成RSA公钥  
     *   
     *   
     * @param modulus  
     *            模  
     * @param exponent  
     *            指数  
     * @return  
     */    
    public static RSAPublicKey getPublicKey(String modulus, String exponent) {    
        try {    
            BigInteger b1 = new BigInteger(modulus,16);
            BigInteger b2 = new BigInteger(exponent,16);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA", new BouncyCastleProvider());
            RSAPublicKeySpec keySpec = new RSAPublicKeySpec(b1, b2);    
            return (RSAPublicKey) keyFactory.generatePublic(keySpec);    
        } catch (Exception e) {    
            e.printStackTrace();    
            return null;    
        }    
    }  
    
    /**  
     * 使用模和指数生成RSA私钥  
      
     * /None/NoPadding】  
     *   
     * @param modulus  
     *            模  
     * @param exponent  
     *            指数  
     * @return  
     */    
    public static RSAPrivateKey getPrivateKey(String modulus, String exponent) {    
        try {    
            BigInteger b1 = new BigInteger(modulus,16);
            BigInteger b2 = new BigInteger(exponent,16);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA", new BouncyCastleProvider());
            RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(b1, b2);    
            return (RSAPrivateKey) keyFactory.generatePrivate(keySpec);    
        } catch (Exception e) {    
            e.printStackTrace();    
            return null;    
        }    
    }


}